/*
 mesh.cpp
 Dynamical
 Matthew Jee
 mcjee@ucsc.edu
*/

#include "mesh.h"

namespace mj {

Mesh::~Mesh() {
    glDeleteBuffers(2, &vertexBufferObject);
}

Mesh::Mesh() {
    glGenBuffers(2, &vertexBufferObject);
    //empty geometry object
}

Mesh::Mesh(GLfloat *vertexData,
           GLuint *indexData,
           int vertexCount,
           int indexCounti,
           int vertexElements) {
    indexCount = indexCounti;
    // The vertex buffer and index buffer are adjacent
    glGenBuffers(2, &vertexBufferObject);
    modifyData(vertexData, indexData, vertexCount, indexCount, vertexElements);
}

// Convenience Constructors

Mesh *Mesh::MakeCube(float width, float height, float depth) {
    float vertexData[] = {
        0.0, 0.0, 0.0,
        width, 0.0, 0.0,
        width, height, 0.0,
        0.0, height, 0.0,

        0.0, 0.0, depth,
        width, 0.0, depth,
        width, height, depth,
        0.0, height, depth,
    };
    GLuint indexData[] = {
        0, 3, 1,
        3, 2, 1,
        1, 2, 5,
        2, 6, 5,
        0, 7, 3,
        0, 4, 7,
        3, 7, 2,
        7, 6, 2,
        4, 5, 7,
        7, 5, 6,
        0, 1, 4,
        1, 5, 4,
    };
    return new Mesh(vertexData, indexData, 8, 36, 3);
}

Mesh *Mesh::MakeWireCube(float width, float height, float depth) {
    float vertexData[] = {
        0.0, 0.0, 0.0,
        width, 0.0, 0.0,
        width, height, 0.0,
        0.0, height, 0.0,

        0.0, 0.0, depth,
        width, 0.0, depth,
        width, height, depth,
        0.0, height, depth,
    };
    GLuint indexData[] = {
        0, 1, 1, 2, 2, 3, 3, 0,
        4, 5, 5, 6, 6, 7, 7, 4,
        1, 5, 2, 6, 3, 7, 0, 4,
    };
    return new Mesh(vertexData, indexData, 8, 24, 3);
}

Mesh *Mesh::MakeSquare(float width, float height) {
    float vertexData[] = {
        0.0, 0.0, 0.0,
        width, 0.0, 0.0,
        width, height, 0.0,
        0.0, height, 0.0,
    };
    GLuint indexData[] = {
        0, 1, 2, 0, 2, 3,
    };
    return new Mesh(vertexData, indexData, 4, 6, 3);
}


// Instance Methods

void Mesh::modifyData(GLfloat *vertexData,
                      GLuint *indexData,
                      int vertexCount,
                      int indexCounti,
                      int vertexElements) {

    indexCount = indexCounti;
    int vertexSize = vertexElements*vertexCount*sizeof(GLfloat);
    int indexSize = indexCount*sizeof(GLuint);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
    glBufferData(GL_ARRAY_BUFFER, vertexSize, vertexData, GL_DYNAMIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexSize, indexData, GL_DYNAMIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

void Mesh::bind(void) {
    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
}

void Mesh::unbind(void) {
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

int Mesh::elementCount(void) {
    return indexCount;
}

}
